"""
均线金叉死叉算法验证工具 (PyEcharts增强可视化版)
功能：验证趋势追踪止损中使用的均线上穿下穿算法
输出：生成一个列表，标记每个K线周期的金叉(上穿)、死叉(下穿)或无信号状态
可视化：使用PyEcharts生成交互式K线图和双均线副图，在副图上用上下箭头标注金死叉
特点：
1. 主图显示K线走势
2. 副图显示双均线(Trading Line和Short Line)
3. 金叉(上穿)用绿色上箭头标注
4. 死叉(下穿)用红色下箭头标注
5. 鼠标悬停可查看详细信息
"""

import numpy as np
import pandas as pd
# matplotlib已被注释，我们使用pyecharts进行可视化
# import matplotlib.pyplot as plt
from tqsdk import TqApi, TqAuth, TqKq
from datetime import datetime
from pyecharts import options as opts
from pyecharts.charts import Kline, Line, Bar, Grid, Scatter
from pyecharts.components import Table
from pyecharts.options import ComponentTitleOpts

# MyTT模块中的函数已在下方直接定义，无需额外导入MyTT库
# 这些是从MyTT库中提取的常用技术指标函数
def REF(Series, N=1):
    """
    向前引用N周期的数据
    """
    return pd.Series(Series).shift(N)

def EMA(Series, N=10):
    """
    指数移动平均线
    """
    return pd.Series(Series).ewm(span=N, adjust=False).mean()

def SUM(Series, N=20):
    """
    求和
    """
    return pd.Series(Series).rolling(N).sum()

def MA(Series, N=5):
    """
    简单移动平均线
    """
    return pd.Series(Series).rolling(N).mean()

def STD(Series, N=20):
    """
    标准差
    """
    return pd.Series(Series).rolling(N).std()

def MACD(Series, FAST=12, SLOW=26, M=9):
    """
    MACD指标
    """
    EMAFAST = EMA(Series, FAST)
    EMASLOW = EMA(Series, SLOW)
    DIFF = EMAFAST - EMASLOW
    DEA = EMA(DIFF, M)
    MACD = (DIFF - DEA) * 2
    return DIFF, DEA, MACD

def calculate_trading_signals(klines):
    """
    计算交易信号
    """
    close = klines.close
    open_price = klines.open
    high = klines.high
    low = klines.low
    
    # 计算Q值
    Q = (close - REF(close, 1)) / REF(close, 1) * 100
    
    # 计算交易线和短线
    terms = [
        26 * Q,
        25 * REF(Q, 1),
        24 * REF(Q, 2),
        23 * REF(Q, 3),
        22 * REF(Q, 4),
        21 * REF(Q, 5),
        20 * REF(Q, 6),
        19 * REF(Q, 7),
        18 * REF(Q, 8),
        17 * REF(Q, 9),
        16 * REF(Q, 10),
        15 * REF(Q, 11),
        14 * REF(Q, 12),
        13 * REF(Q, 13),
        12 * REF(Q, 14),
        11 * REF(Q, 15),
        10 * REF(Q, 16),
        9 * REF(Q, 17),
        8 * REF(Q, 18),
        7 * REF(Q, 19),
        6 * REF(Q, 20),
        5 * REF(Q, 21),
        4 * REF(Q, 22),
        3 * REF(Q, 23),
        2 * REF(Q, 24),
        REF(Q, 25)
    ]
    
    trading_line = sum(terms) / 351
    short_line = EMA(trading_line, 7)
    
    # 创建结果DataFrame
    result = pd.DataFrame({
        'datetime': klines.datetime,
        'open': open_price,
        'high': high,
        'low': low,
        'close': close,
        'trading_line': trading_line,
        'short_line': short_line
    })
    
    # 转换时间戳为日期时间对象 - 修复版
    # 天勤SDK可能返回纳秒级时间戳，需要先转换为合适的格式
    # 检测时间戳的大小，如果太大则可能是纳秒级
    sample_ts = result['datetime'].iloc[0] if len(result) > 0 else 0
    if sample_ts > 1e15:  # 纳秒级时间戳
        result['date'] = pd.to_datetime(result['datetime'] / 1e9, unit='s')
    elif sample_ts > 1e12:  # 微秒级时间戳
        result['date'] = pd.to_datetime(result['datetime'] / 1e6, unit='s')
    elif sample_ts > 1e9:  # 毫秒级时间戳
        result['date'] = pd.to_datetime(result['datetime'] / 1e3, unit='s')
    else:  # 秒级时间戳
        result['date'] = pd.to_datetime(result['datetime'], unit='s')
    
    # 添加日期字符串列，用于图表显示
    result['date_str'] = result['date'].dt.strftime('%Y-%m-%d')
    
    # 计算信号
    result['signal'] = np.nan  # 默认为NaN
    
    # 计算上穿下穿信号
    for i in range(2, len(result)):
        # 上穿信号: 前一周期trading_line < short_line，当前周期trading_line > short_line
        if (result.trading_line.iloc[i-1] < result.short_line.iloc[i-1] and 
            result.trading_line.iloc[i] > result.short_line.iloc[i]):
            result.loc[result.index[i], 'signal'] = '上穿'
        
        # 下穿信号: 前一周期trading_line > short_line，当前周期trading_line < short_line
        elif (result.trading_line.iloc[i-1] > result.short_line.iloc[i-1] and 
              result.trading_line.iloc[i] < result.short_line.iloc[i]):
            result.loc[result.index[i], 'signal'] = '下穿'
    
    return result

# 安全的日期格式化函数
def safe_date_format(dt_value):
    """
    安全地格式化日期时间值，处理各种可能的格式
    增强版：处理天勤SDK可能返回的各种时间戳格式（秒/毫秒/微秒/纳秒）
    """
    if pd.isna(dt_value):
        return "N/A"
    
    try:
        # 如果是pandas Timestamp或datetime对象
        if hasattr(dt_value, 'strftime'):
            return dt_value.strftime('%Y-%m-%d')  # 只显示日期部分，不显示时间
        
        # 如果是时间戳（整数或浮点数）- 根据大小判断单位
        if isinstance(dt_value, (int, float)):
            # 根据时间戳大小判断单位
            try:
                if dt_value > 1e15:  # 纳秒级时间戳
                    return datetime.fromtimestamp(dt_value / 1e9).strftime('%Y-%m-%d')
                elif dt_value > 1e12:  # 微秒级时间戳
                    return datetime.fromtimestamp(dt_value / 1e6).strftime('%Y-%m-%d')
                elif dt_value > 1e9:  # 毫秒级时间戳
                    return datetime.fromtimestamp(dt_value / 1e3).strftime('%Y-%m-%d')
                else:  # 秒级时间戳
                    return datetime.fromtimestamp(dt_value).strftime('%Y-%m-%d')
            except Exception:
                # 如果时间戳转换失败，尝试不同的方法
                pass
        
        # 尝试使用pandas的to_datetime，尝试不同的单位
        for unit in ['s', 'ms', 'us', 'ns']:
            try:
                return pd.to_datetime(dt_value, unit=unit).strftime('%Y-%m-%d')
            except Exception:
                continue
                
        # 尝试使用pandas的to_datetime，不指定unit
        try:
            return pd.to_datetime(dt_value).strftime('%Y-%m-%d')
        except Exception:
            pass
    except Exception:
        pass
        
    # 如果所有尝试都失败，返回原始值的字符串表示
    return str(dt_value)

def create_pyecharts_visualization(result, symbol, period_name):
    """
    使用PyEcharts创建可视化图表
    增强版：K线图和双均线副图，使用金叉死叉箭头标注
    """
    # 准备数据 - 使用预先格式化的日期字符串
    date_list = result['date_str'].tolist()
    kline_data = [[float(result['open'].iloc[i]), 
                  float(result['close'].iloc[i]), 
                  float(result['low'].iloc[i]), 
                  float(result['high'].iloc[i])] for i in range(len(result))]
    
    trading_line_data = [float(val) if not pd.isna(val) else None for val in result['trading_line']]
    short_line_data = [float(val) if not pd.isna(val) else None for val in result['short_line']]
    
    # 准备上穿下穿点数据（金叉死叉）
    up_cross = result[result['signal'] == '上穿']
    down_cross = result[result['signal'] == '下穿']
    
    # 使用索引位置而不是日期字符串来定位点，避免日期格式化问题
    try:
        # 尝试使用索引方法
        up_cross_indices = up_cross.index.tolist()
        up_cross_x = [i for i in range(len(result)) if i in up_cross_indices]
        up_cross_y = [float(val) for val in up_cross['trading_line']]
        up_cross_dates = [result['date_str'].iloc[i] if i < len(result) else f"数据点-{i}" for i in up_cross_indices]
        up_cross_values = [f"金叉: {val:.4f}" for val in up_cross['trading_line']]
        
        down_cross_indices = down_cross.index.tolist()
        down_cross_x = [i for i in range(len(result)) if i in down_cross_indices]
        down_cross_y = [float(val) for val in down_cross['trading_line']]
        down_cross_dates = [result['date_str'].iloc[i] if i < len(result) else f"数据点-{i}" for i in down_cross_indices]
        down_cross_values = [f"死叉: {val:.4f}" for val in down_cross['trading_line']]
    except Exception as e:
        print(f"处理交叉点数据时出错: {e}")
        print("使用备用方法...")
        
        # 备用方法：直接使用行号
        up_cross_x = up_cross.index.tolist()
        up_cross_y = [float(val) if not pd.isna(val) else 0 for val in up_cross['trading_line']]
        up_cross_dates = [f"上穿点-{i}" for i in range(len(up_cross))]
        up_cross_values = [f"金叉: {val:.4f}" for val in up_cross_y]
        
        down_cross_x = down_cross.index.tolist()
        down_cross_y = [float(val) if not pd.isna(val) else 0 for val in down_cross['trading_line']]
        down_cross_dates = [f"下穿点-{i}" for i in range(len(down_cross))]
        down_cross_values = [f"死叉: {val:.4f}" for val in down_cross_y]
    
    # 创建K线图
    kline = (
        Kline()
        .add_xaxis(date_list)
        .add_yaxis(
            "K线",
            kline_data,
            itemstyle_opts=opts.ItemStyleOpts(
                color="#ec0000",  # 阳线颜色
                color0="#00da3c",  # 阴线颜色
                border_color="#8A0000",  # 阳线边框颜色
                border_color0="#008F28",  # 阴线边框颜色
            ),
        )
        .set_global_opts(
            title_opts=opts.TitleOpts(
                title=f"{symbol} {period_name} K线图",
                subtitle="趋势追踪止损策略验证",
                pos_left="center",
                title_textstyle_opts=opts.TextStyleOpts(
                    font_size=16,
                    font_weight="bold"
                ),
                subtitle_textstyle_opts=opts.TextStyleOpts(
                    font_size=12
                )
            ),
            xaxis_opts=opts.AxisOpts(
                type_="category",
                is_scale=True,
                boundary_gap=False,
                axisline_opts=opts.AxisLineOpts(is_on_zero=False),
                splitline_opts=opts.SplitLineOpts(is_show=False),
                split_number=20,
                min_="dataMin",
                max_="dataMax",
                axislabel_opts=opts.LabelOpts(
                    rotate=30,  # 旋转标签以避免重叠
                    font_size=10,
                    interval="auto"  # 自动计算间隔
                ),
            ),
            yaxis_opts=opts.AxisOpts(
                is_scale=True,
                splitline_opts=opts.SplitLineOpts(is_show=True),
                axislabel_opts=opts.LabelOpts(formatter="{value}"),
            ),
            tooltip_opts=opts.TooltipOpts(
                trigger="axis", 
                axis_pointer_type="cross",
                background_color="rgba(245, 245, 245, 0.8)",
                border_width=1,
                border_color="#ccc",
                textstyle_opts=opts.TextStyleOpts(color="#000"),
                formatter="""
                function(params) {
                    const date = params[0].name;
                    let res = `<div style="font-weight:bold;margin-bottom:3px;">${date}</div>`;
                    
                    for (let i = 0; i < params.length; i++) {
                        const param = params[i];
                        const color = param.color;
                        const seriesName = param.seriesName;
                        let value = '';
                        
                        if (seriesName === 'K线') {
                            value = `开盘: ${param.data[1]}<br/>
                                    收盘: ${param.data[2]}<br/>
                                    最低: ${param.data[3]}<br/>
                                    最高: ${param.data[4]}`;
                        } else {
                            value = param.data;
                        }
                        
                        res += `<div style="display:flex;align-items:center;margin-top:3px;">
                                <div style="height:10px;width:10px;border-radius:50%;background-color:${color};margin-right:5px;"></div>
                                <div style="font-weight:bold;">${seriesName}: </div>
                                <div style="margin-left:5px;">${value}</div>
                                </div>`;
                    }
                    
                    return res;
                }
                """,
            ),
            datazoom_opts=[
                # 底部滑动条，同时控制主图和副图
                opts.DataZoomOpts(
                    is_show=True,
                    type_="slider",
                    pos_bottom="3%",
                    range_start=70,  # 默认显示最后30%的数据
                    range_end=100,
                    xaxis_index=[0, 1],  # 同时控制主图和副图的x轴
                ),
                # 主图内部缩放，同时控制主图和副图
                opts.DataZoomOpts(
                    is_show=False,
                    type_="inside",
                    range_start=70,
                    range_end=100,
                    xaxis_index=[0, 1],  # 同时控制主图和副图的x轴
                    orient="horizontal",
                ),
                # 副图内部缩放，同时控制主图和副图
                opts.DataZoomOpts(
                    is_show=False,
                    type_="inside",
                    range_start=70,
                    range_end=100,
                    xaxis_index=[0, 1],  # 同时控制主图和副图的x轴
                    orient="horizontal",
                ),
            ],
            legend_opts=opts.LegendOpts(
                is_show=True,
                pos_top="3%",
                pos_left="center",
                orient="horizontal",
                item_gap=25,  # 增加图例项之间的间距
            ),
        )
    )
    
    # 创建均线图（副图）
    line = (
        Line()
        .add_xaxis(date_list)
        .add_yaxis(
            "Trading Line",
            trading_line_data,
            is_smooth=True,
            linestyle_opts=opts.LineStyleOpts(width=2, color="#1E90FF"),  # 深蓝色
            label_opts=opts.LabelOpts(is_show=False),
            symbol="emptyCircle",
            symbol_size=3,
            tooltip_opts=opts.TooltipOpts(formatter="{a}: {c}"),
        )
        .add_yaxis(
            "Short Line",
            short_line_data,
            is_smooth=True,
            linestyle_opts=opts.LineStyleOpts(width=2, color="#FF4500"),  # 橙红色
            label_opts=opts.LabelOpts(is_show=False),
            symbol="emptyCircle",
            symbol_size=3,
            tooltip_opts=opts.TooltipOpts(formatter="{a}: {c}"),
        )
        .set_global_opts(
            title_opts=opts.TitleOpts(
                title=f"{symbol} {period_name} 均线金叉死叉信号",
                subtitle="Trading Line与Short Line交叉信号",
                pos_left="center",
                pos_top="48%",  # 稍微上移标题位置
                title_textstyle_opts=opts.TextStyleOpts(
                    font_size=16,
                    font_weight="bold"
                ),
                subtitle_textstyle_opts=opts.TextStyleOpts(
                    font_size=12
                )
            ),
            xaxis_opts=opts.AxisOpts(
                type_="category",
                grid_index=1,
                is_scale=True,
                boundary_gap=False,
                axisline_opts=opts.AxisLineOpts(is_on_zero=False),
                splitline_opts=opts.SplitLineOpts(is_show=False),
                split_number=20,
                min_="dataMin",
                max_="dataMax",
                axislabel_opts=opts.LabelOpts(
                    rotate=30,  # 旋转标签以避免重叠
                    font_size=10,
                    interval="auto"  # 自动计算间隔
                ),
            ),
            yaxis_opts=opts.AxisOpts(
                grid_index=1,
                is_scale=True,
                splitline_opts=opts.SplitLineOpts(is_show=True),
                axislabel_opts=opts.LabelOpts(formatter="{value}"),
            ),
            tooltip_opts=opts.TooltipOpts(
                trigger="axis", 
                axis_pointer_type="cross",
                background_color="rgba(245, 245, 245, 0.8)",
                border_width=1,
                border_color="#ccc",
                textstyle_opts=opts.TextStyleOpts(color="#000"),
                formatter="""
                function(params) {
                    const date = params[0].name;
                    let res = `<div style="font-weight:bold;margin-bottom:3px;">${date}</div>`;
                    
                    for (let i = 0; i < params.length; i++) {
                        const param = params[i];
                        const color = param.color;
                        const seriesName = param.seriesName;
                        let value = '';
                        
                        if (seriesName === 'K线') {
                            value = `开盘: ${param.data[1]}<br/>
                                    收盘: ${param.data[2]}<br/>
                                    最低: ${param.data[3]}<br/>
                                    最高: ${param.data[4]}`;
                        } else {
                            value = param.data;
                        }
                        
                        res += `<div style="display:flex;align-items:center;margin-top:3px;">
                                <div style="height:10px;width:10px;border-radius:50%;background-color:${color};margin-right:5px;"></div>
                                <div style="font-weight:bold;">${seriesName}: </div>
                                <div style="margin-left:5px;">${value}</div>
                                </div>`;
                    }
                    
                    return res;
                }
                """,
            ),
            datazoom_opts=[
                # 底部滑动条，同时控制主图和副图
                opts.DataZoomOpts(
                    is_show=True,
                    type_="slider",
                    pos_bottom="3%",
                    range_start=70,  # 默认显示最后30%的数据
                    range_end=100,
                    xaxis_index=[0, 1],  # 同时控制主图和副图的x轴
                ),
                # 主图内部缩放，同时控制主图和副图
                opts.DataZoomOpts(
                    is_show=False,
                    type_="inside",
                    range_start=70,
                    range_end=100,
                    xaxis_index=[0, 1],  # 同时控制主图和副图的x轴
                    orient="horizontal",
                ),
                # 副图内部缩放，同时控制主图和副图
                opts.DataZoomOpts(
                    is_show=False,
                    type_="inside",
                    range_start=70,
                    range_end=100,
                    xaxis_index=[0, 1],  # 同时控制主图和副图的x轴
                    orient="horizontal",
                ),
            ],
            legend_opts=opts.LegendOpts(
                is_show=True,
                pos_top="52%",
                pos_left="center",
                orient="horizontal",
                item_gap=25,  # 增加图例项之间的间距
            ),
        )
    )
    
    # 创建金叉点散点图（上穿）
    up_scatter = (
        Scatter()
        .add_xaxis(up_cross_x)
        .add_yaxis(
            "金叉",
            up_cross_y,
            symbol_size=25,
            symbol="triangle",  # 使用三角形符号
            itemstyle_opts=opts.ItemStyleOpts(color="#00FF00", opacity=0.8),  # 亮绿色，半透明
            label_opts=opts.LabelOpts(
                is_show=True,
                position="top",
                formatter="金叉",
                font_size=12,
                font_weight="bold",
                color="#006400"  # 深绿色
            ),
            tooltip_opts=opts.TooltipOpts(
                formatter=lambda params: (
                    f"<div style='font-weight:bold;color:#006400;'>金叉信号</div>"
                    f"<div>日期: {up_cross_dates[params.dataIndex]}</div>"
                    f"<div>Trading Line: {up_cross_values[params.dataIndex]}</div>"
                ),
                background_color="rgba(240, 255, 240, 0.9)",  # 浅绿色背景
                border_color="#00FF00",
                border_width=1
            )
        )
    )
    
    # 创建死叉点散点图（下穿）
    down_scatter = (
        Scatter()
        .add_xaxis(down_cross_x)
        .add_yaxis(
            "死叉",
            down_cross_y,
            symbol_size=25,
            symbol="triangle-down",  # 使用向下三角形符号
            itemstyle_opts=opts.ItemStyleOpts(color="#FF0000", opacity=0.8),  # 亮红色，半透明
            label_opts=opts.LabelOpts(
                is_show=True,
                position="bottom",
                formatter="死叉",
                font_size=12,
                font_weight="bold",
                color="#8B0000"  # 深红色
            ),
            tooltip_opts=opts.TooltipOpts(
                formatter=lambda params: (
                    f"<div style='font-weight:bold;color:#8B0000;'>死叉信号</div>"
                    f"<div>日期: {down_cross_dates[params.dataIndex]}</div>"
                    f"<div>Trading Line: {down_cross_values[params.dataIndex]}</div>"
                ),
                background_color="rgba(255, 240, 240, 0.9)",  # 浅红色背景
                border_color="#FF0000",
                border_width=1
            )
        )
    )
    
    # 创建网格布局 - 优化版，确保主图和副图完美对齐
    grid = (
        Grid(init_opts=opts.InitOpts(
            width="1280px",  # 增加宽度
            height="900px",  # 增加高度
            theme="white",
            animation_opts=opts.AnimationOpts(
                animation=True,
                animation_threshold=2000,
                animation_duration=1000,
                animation_easing="cubicOut"
            ),
            page_title=f"{symbol} {period_name} 金叉死叉分析 - 趋势追踪止损策略验证"
        ))
        .add(kline, grid_opts=opts.GridOpts(
            pos_left="10%", 
            pos_right="5%", 
            height="40%",  # 增加主图高度
            is_contain_label=True
        ))
        .add(line, grid_opts=opts.GridOpts(
            pos_left="10%", 
            pos_right="5%", 
            pos_top="58%",  # 调整副图位置
            height="38%",  # 增加副图高度
            is_contain_label=True
        ))
        .add(up_scatter, grid_opts=opts.GridOpts(
            pos_left="10%", 
            pos_right="5%", 
            pos_top="58%",  # 与副图保持一致
            height="38%"  # 与副图保持一致
        ))
        .add(down_scatter, grid_opts=opts.GridOpts(
            pos_left="10%", 
            pos_right="5%", 
            pos_top="58%",  # 与副图保持一致
            height="38%"  # 与副图保持一致
        ))
    )
    
    # 保存为HTML文件
    html_filename = f"{symbol.replace('.', '_')}_{period_name}_金叉死叉分析.html"
    grid.render(html_filename)
    
    return html_filename

# 主函数
print("开始验证均线上穿下穿算法...")

try:
    # 创建API连接
    api = TqApi(account=TqKq(), auth=TqAuth("cps168", "alibaba"))
    
    # 设置默认合约和周期
    symbol = "SHFE.ao2601"  # 上期所氧化铝
    period = 86400  # 日线
    period_name = "日线"
    
    print(f"正在获取 {symbol} 的{period_name}数据...")
    klines = api.get_kline_serial(symbol, period, data_length=1000)  # 增加数据长度以获取更多历史数据
    
    # 调试输出，查看时间戳格式
    if len(klines) > 0:
        sample_ts = klines.datetime[0]
        print(f"调试信息 - 时间戳样本: {sample_ts}, 类型: {type(sample_ts)}")
        print(f"时间戳位数: {len(str(int(sample_ts)))}")
        
        # 尝试不同的转换方式
        try:
            print(f"作为秒级时间戳: {datetime.fromtimestamp(sample_ts)}")
        except Exception as e:
            print(f"秒级转换失败: {e}")
            
        try:
            print(f"作为毫秒级时间戳: {datetime.fromtimestamp(sample_ts/1000)}")
        except Exception as e:
            print(f"毫秒级转换失败: {e}")
            
        try:
            print(f"作为纳秒级时间戳: {datetime.fromtimestamp(sample_ts/1000000000)}")
        except Exception as e:
            print(f"纳秒级转换失败: {e}")
    
    # 计算信号，添加异常处理
    try:
        result = calculate_trading_signals(klines)
    except Exception as e:
        print(f"计算信号时出错: {e}")
        print("尝试使用备用方法处理时间戳...")
        
        # 备用方法：直接使用索引作为日期标识
        close = klines.close
        open_price = klines.open
        high = klines.high
        low = klines.low
        
        # 计算Q值
        Q = (close - REF(close, 1)) / REF(close, 1) * 100
        
        # 计算交易线和短线
        terms = [
            26 * Q,
            25 * REF(Q, 1),
            24 * REF(Q, 2),
            23 * REF(Q, 3),
            22 * REF(Q, 4),
            21 * REF(Q, 5),
            20 * REF(Q, 6),
            19 * REF(Q, 7),
            18 * REF(Q, 8),
            17 * REF(Q, 9),
            16 * REF(Q, 10),
            15 * REF(Q, 11),
            14 * REF(Q, 12),
            13 * REF(Q, 13),
            12 * REF(Q, 14),
            11 * REF(Q, 15),
            10 * REF(Q, 16),
            9 * REF(Q, 17),
            8 * REF(Q, 18),
            7 * REF(Q, 19),
            6 * REF(Q, 20),
            5 * REF(Q, 21),
            4 * REF(Q, 22),
            3 * REF(Q, 23),
            2 * REF(Q, 24),
            REF(Q, 25)
        ]
        
        trading_line = sum(terms) / 351
        short_line = EMA(trading_line, 7)
        
        # 创建结果DataFrame，不使用日期时间
        result = pd.DataFrame({
            'datetime': range(len(klines)),  # 使用索引代替时间戳
            'open': open_price,
            'high': high,
            'low': low,
            'close': close,
            'trading_line': trading_line,
            'short_line': short_line
        })
        
        # 添加日期字符串列，使用索引作为替代
        result['date_str'] = [f"数据点-{i}" for i in range(len(result))]
        
        # 计算信号
        result['signal'] = np.nan  # 默认为NaN
        
        # 计算上穿下穿信号
        for i in range(2, len(result)):
            # 上穿信号: 前一周期trading_line < short_line，当前周期trading_line > short_line
            if (result.trading_line.iloc[i-1] < result.short_line.iloc[i-1] and 
                result.trading_line.iloc[i] > result.short_line.iloc[i]):
                result.loc[result.index[i], 'signal'] = '上穿'
            
            # 下穿信号: 前一周期trading_line > short_line，当前周期trading_line < short_line
            elif (result.trading_line.iloc[i-1] > result.short_line.iloc[i-1] and 
                  result.trading_line.iloc[i] < result.short_line.iloc[i]):
                result.loc[result.index[i], 'signal'] = '下穿'
    
    # 输出结果摘要
    print("\n计算完成! 结果摘要:")
    print(f"总K线数量: {len(result)}")
    print(f"上穿信号数量: {result['signal'].value_counts().get('上穿', 0)}")
    print(f"下穿信号数量: {result['signal'].value_counts().get('下穿', 0)}")
    
    # 显示最近的10个信号
    recent_signals = result[result['signal'].notna()].tail(10)
    if not recent_signals.empty:
        print("\n最近的10个信号:")
        for idx, row in recent_signals.iterrows():
            # 使用安全的日期格式化函数
            date_str = safe_date_format(row.get('date', row.get('datetime')))
            print(f"{date_str}: {row['signal']} (trading_line: {row['trading_line']:.2f}, short_line: {row['short_line']:.2f})")
    
    # 保存结果到CSV
    csv_filename = f"{symbol.replace('.', '_')}_{period_name}_信号.csv"
    result.to_csv(csv_filename, index=False)
    print(f"\n结果已保存到文件: {csv_filename}")

    # 使用PyEcharts创建可视化图表
    try:
        html_filename = create_pyecharts_visualization(result, symbol, period_name)
        print("\n" + "="*80)
        print(f"【可视化结果】PyEcharts交互式图表已生成")
        print(f"文件路径: {html_filename}")
        print(f"请在浏览器中打开此文件查看K线图和双均线金叉死叉分析图")
        print("-"*80)
        print(f"【信号统计】")
        print(f"金叉信号数量: {result['signal'].value_counts().get('上穿', 0)}")
        print(f"死叉信号数量: {result['signal'].value_counts().get('下穿', 0)}")
        print(f"总信号数量: {result['signal'].notna().sum()}")
        print(f"信号占比: {(result['signal'].notna().sum() / len(result) * 100):.2f}%")
        print("="*80)
    except Exception as e:
        print(f"生成可视化图表时出错: {e}")
        html_filename = None
    if html_filename:
        print(f"文件路径: {html_filename}")
        print(f"请在浏览器中打开此文件查看K线图和双均线金叉死叉分析图")
        print("-"*80)
        print(f"【信号统计】")
        print(f"金叉信号数量: {result['signal'].value_counts().get('上穿', 0)}")
        print(f"死叉信号数量: {result['signal'].value_counts().get('下穿', 0)}")
        print(f"总信号数量: {result['signal'].notna().sum()}")
        print(f"信号占比: {(result['signal'].notna().sum() / len(result) * 100):.2f}%")
        print("="*80)
    

    
    # matplotlib图表部分已被注释，我们使用pyecharts进行可视化
    # 如果需要使用matplotlib，请取消下面代码的注释
    """
    # 导入matplotlib
    import matplotlib.pyplot as plt
    
    plt.figure(figsize=(15, 10))
    
    # 绘制收盘价
    plt.subplot(2, 1, 1)
    # 使用索引作为X轴，避免日期转换问题
    plt.plot(result.index, result['close'], label='收盘价', color='black', alpha=0.6)
    plt.title(f"{symbol} {period_name} 收盘价")
    plt.legend()
    plt.grid(True)
    
    # 绘制均线和信号
    plt.subplot(2, 1, 2)
    plt.plot(result.index, result['trading_line'], label='Trading Line', color='blue')
    plt.plot(result.index, result['short_line'], label='Short Line', color='red')
    
    # 设置x轴刻度，每10个点显示一个日期标签
    if len(result) > 0:
        x_ticks = np.arange(0, len(result), max(1, len(result) # 10))
        plt.xticks(x_ticks)
    
    # 标记上穿和下穿点
    up_cross = result[result['signal'] == '上穿']
    down_cross = result[result['signal'] == '下穿']
    
    plt.scatter(up_cross.index, up_cross['trading_line'], color='green', marker='^', s=100, label='金叉')
    plt.scatter(down_cross.index, down_cross['trading_line'], color='red', marker='v', s=100, label='死叉')
    
    plt.title(f"{symbol} {period_name} 均线和信号")
    plt.legend()
    plt.grid(True)
    
    # 保存图表
    plt_filename = f"{symbol.replace('.', '_')}_{period_name}_图表.png"
    plt.savefig(plt_filename)
    print(f"Matplotlib静态图表已保存到文件: {plt_filename}")
    
    # 显示图表
    plt.tight_layout()
    plt.show()
    """
    
    print("已使用PyEcharts生成增强版可视化图表，包含K线图和双均线金叉死叉标注")
    
except Exception as e:
    print(f"发生错误: {e}")
    # 打印更详细的错误信息
    import traceback
    traceback.print_exc()
finally:
    if 'api' in locals():
        api.close()
        print("API连接已关闭")